﻿using Avalonia.Controls;
using LightCAD.Core.Elements.Basic;
using LightCAD.Runtime.Interface;
using System.ComponentModel;

namespace LightCAD.Drawing.Actions.Action
{
    public class TableAction : ElementAction
    {
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;

        public TableAction() { }
        public TableAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令 ：Table");
        }

        static TableAction()
        {
            CommandName = "Table";
            CreateMethods = new LcCreateMethod[2];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = TableInsertWay.BP.ToString(),
                Description = TableInsertWay.BP.GetDescription(),
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="Step_ColumnCount", Options="指定列数：" },
                    new LcCreateStep{ Name="Step_RowCount", Options="指定行数：" },
                    new LcCreateStep{ Name="Step_ColumnWidth", Options="指定列宽：" },
                    new LcCreateStep{ Name="Step_RowHeight", Options="指定行高：" },
                    new LcCreateStep{ Name="Step_CellType1", Options="指定第一行单元样式（标题|表头|数据）：" },
                    new LcCreateStep{ Name="Step_CellType2", Options="指定第二行单元样式（标题|表头|数据）：" },
                    new LcCreateStep{ Name="Step_CellType3", Options="指定所有其他行单元样式（标题|表头|数据）：" },
                    new LcCreateStep{ Name="Step_StartPoint", Options="指定插入坐标：" },
                }
            };

            CreateMethods[1] = new LcCreateMethod()
            {
                Name = TableInsertWay.BW.ToString(),
                Description = TableInsertWay.BW.GetDescription(),
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="Step_ColumnCount", Options="指定列数：" },
                    new LcCreateStep{ Name="Step_RowHeight", Options="指定行高：" },
                    new LcCreateStep{ Name="Step_CellType1", Options="指定第一行单元样式（标题|表头|数据）：" },
                    new LcCreateStep{ Name="Step_CellType2", Options="指定第二行单元样式（标题|表头|数据）：" },
                    new LcCreateStep{ Name="Step_CellType3", Options="指定所有其他行单元样式（标题|表头|数据）：" },
                    new LcCreateStep{ Name="Step_StartPoint", Options="指定开始坐标：" },
                    new LcCreateStep{ Name="Step_EndPoint", Options="指定结束坐标：" },
                }
            };
        }

        internal static void Initilize()
        {
            ElementActions.Table = new TableAction();
            LcDocument.ElementActions.Add(BuiltinElementType.Table, ElementActions.Table);
        }

        private PointInputer inputer;

        // 插入方式
        public TableInsertWay insertWay; 

        // 列数
        public int columnCount = 5;
        // 行数
        public int rowCount = 1;
        // 列宽
        public double columnWidth = 63.5 * 20;
        // 实际行高 rowHeight * height
        // 行高
        public int rowHeight = 1;
        // 默认高度
        private double height = 9.5 * 20;
        // 单元格样式
        public CellType[] cellTypes = new CellType[] { CellType.Title, CellType.Header, CellType.Data };
        // 开始坐标
        private Vector2 firstPoint;
        // 结束坐标
        private Vector2 endPoint;

        private string _methodName;

        private LcCreateMethod GetMethod(string method)
        {
            if (method == null)
                return SetCurMethod(CreateMethods, 0);

            int getted = CreateMethods.ToList().FindIndex(m => m.Name == method);
            if (getted == -1)
                return SetCurMethod(CreateMethods, 0);
            else
                return SetCurMethod(CreateMethods, getted);
        }

        public async void ExecCreate(string[] args = null)
        {
            var method = TableInsertWay.BP.ToString();
            bool isUI = false;
            if (args != null && args.Length > 0)
            {
                if (args[0] == "UI")
                {
                    var win = (ITableWindow)AppRuntime.UISystem.CreateWindow("TableWindow", this);
                    var result = AppRuntime.UISystem.ShowDialog(win);
                    if (result == LcDialogResult.OK)
                    {
                        isUI = true;
                        if (insertWay == TableInsertWay.BP)
                        {
                            method = TableInsertWay.BP.ToString();
                        }
                        else if (insertWay == TableInsertWay.BW)
                        {
                            method = TableInsertWay.BW.ToString();
                        }
                    }
                    else
                    {
                        return;
                    }
                }
                else
                {
                    method = args[0];
                }
            }
            var curMethod = this.GetMethod(method);
            _methodName = curMethod.Name;

            this.StartCreating();
            this.inputer = new PointInputer(this.docEditor);

            if (curMethod.Name == TableInsertWay.BP.ToString())
            {
                if (!isUI)
                {
                    goto Step0;
                }
                goto Step7;
            }
            if (curMethod.Name == TableInsertWay.BW.ToString())
            {
                if (!isUI)
                {
                    goto Method_Window_Step0;
                }
                goto Method_Window_Step5;
            }

            #region ByPoint
            Step0:
                var step0 = curMethod.Steps[0];
                var result0 = await inputer.Execute(step0.Options);
                if (inputer.isCancelled || result0 == null) { this.Cancel(); goto End; }
                if (result0.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(result0.Option) && int.TryParse(result0.Option, out int tmp))
                    {
                        columnCount = tmp;
                    }
                    // 格式不对直接使用默认值
                    goto Step1;
                }
                goto Step0;
            Step1:
                var step1 = curMethod.Steps[1];
                var result1 = await inputer.Execute(step1.Options);
                if (inputer.isCancelled || result1 == null) { this.Cancel(); goto End; }

                if (result1.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(result1.Option) && int.TryParse(result1.Option, out int tmp))
                    {
                        rowCount = tmp;
                    }
                    // 格式不对直接使用默认值
                    goto Step2;
                }
                goto Step1;
            Step2:
                var step2 = curMethod.Steps[2];
                var result2 = await inputer.Execute(step2.Options);
                if (inputer.isCancelled || result2 == null) { this.Cancel(); goto End; }

                if (result2.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(result2.Option) && double.TryParse(result2.Option, out double tmp))
                    {
                        columnWidth = tmp;
                    }
                    // 格式不对直接使用默认值
                    goto Step3;
                }
                goto Step2;
            Step3:
                var step3 = curMethod.Steps[3];
                var result3 = await inputer.Execute(step3.Options);
                if (inputer.isCancelled || result3 == null) { this.Cancel(); goto End; }

                if (result3.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(result3.Option) && int.TryParse(result3.Option, out int tmp))
                    {
                        rowHeight = tmp;
                    }
                    // 格式不对直接使用默认值
                    goto Step4;
                }
                goto Step3;
            Step4:
                var step4 = curMethod.Steps[4];
                var result4 = await inputer.Execute(step4.Options);
                if (inputer.isCancelled || result4 == null) { this.Cancel(); goto End; }

                if (result4.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(result4.Option.Trim()))
                    {
                        // 此处转换错误，会直接使用最后一项
                        cellTypes[0] = EnumExtensions.GetEnumValueFromDescription<CellType>(result4.Option);
                    }
                    goto Step5;
                }
                goto Step4;
            Step5:
                var step5 = curMethod.Steps[5];
                var result5 = await inputer.Execute(step5.Options);
                if (inputer.isCancelled || result5 == null) { this.Cancel(); goto End; }

                if (result5.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(result5.Option.Trim()))
                    {
                        // 此处转换错误，会直接使用最后一项
                        cellTypes[1] = EnumExtensions.GetEnumValueFromDescription<CellType>(result5.Option);
                    }
                    goto Step6;
                }
                goto Step5;
            Step6:
                var step6 = curMethod.Steps[6];
                var result6 = await inputer.Execute(step6.Options);
                if (inputer.isCancelled || result6 == null) { this.Cancel(); goto End; }

                if (result6.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(result6.Option.Trim()))
                    {
                        // 此处转换错误，会直接使用最后一项
                        cellTypes[2] = EnumExtensions.GetEnumValueFromDescription<CellType>(result6.Option);
                    }
                    goto Step7;
                }
                goto Step6;
            Step7:
                var step7 = curMethod.Steps[7];
                var result7 = await inputer.Execute(step7.Options);
                if (inputer.isCancelled || result7 == null) { this.Cancel(); goto End; }

                if (result7.ValueX == null)
                {
                    goto Step7;
                }
                else
                {
                    this.firstPoint = (Vector2)result7.ValueX;
                }

                CreateTable();
                goto End;
            #endregion

            #region ByWindow
            Method_Window_Step0:
                var win_step0 = curMethod.Steps[0];
                var win_result0 = await inputer.Execute(win_step0.Options);
                if (inputer.isCancelled || win_result0 == null) { this.Cancel(); goto End; }
                if (win_result0.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(win_result0.Option) && int.TryParse(win_result0.Option, out int tmp))
                    {
                        columnCount = tmp;
                    }
                    // 格式不对直接使用默认值
                    goto Method_Window_Step1;
                }
                goto Method_Window_Step0;
            Method_Window_Step1:
                var win_step1 = curMethod.Steps[1];
                var win_result1 = await inputer.Execute(win_step1.Options);
                if (inputer.isCancelled || win_result1 == null) { this.Cancel(); goto End; }

                if (win_result1.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(win_result1.Option) && int.TryParse(win_result1.Option, out int tmp))
                    {
                        rowHeight = tmp;
                    }
                    // 格式不对直接使用默认值
                    goto Method_Window_Step2;
                }
                goto Method_Window_Step1;
            Method_Window_Step2:
                var win_step2 = curMethod.Steps[2];
                var win_result2 = await inputer.Execute(win_step2.Options);
                if (inputer.isCancelled || win_result2 == null) { this.Cancel(); goto End; }

                if (win_result2.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(win_result2.Option.Trim()))
                    {
                        // 此处转换错误，会直接使用最后一项
                        cellTypes[0] = EnumExtensions.GetEnumValueFromDescription<CellType>(win_result2.Option);
                    }
                    goto Method_Window_Step3;
                }
                goto Method_Window_Step2;
            Method_Window_Step3:
                var win_step3 = curMethod.Steps[3];
                var win_result3 = await inputer.Execute(win_step3.Options);
                if (inputer.isCancelled || win_result3 == null) { this.Cancel(); goto End; }

                if (win_result3.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(win_result3.Option.Trim()))
                    {
                        // 此处转换错误，会直接使用最后一项
                        cellTypes[1] = EnumExtensions.GetEnumValueFromDescription<CellType>(win_result3.Option);
                    }
                    goto Method_Window_Step4;
                }
                goto Method_Window_Step3;
            Method_Window_Step4:
                var win_step4 = curMethod.Steps[4];
                var win_result4 = await inputer.Execute(win_step4.Options);
                if (inputer.isCancelled || win_result4 == null) { this.Cancel(); goto End; }

                if (win_result4.ValueX == null)
                {
                    if (!string.IsNullOrEmpty(win_result4.Option.Trim()))
                    {
                        // 此处转换错误，会直接使用最后一项
                        cellTypes[2] = EnumExtensions.GetEnumValueFromDescription<CellType>(win_result4.Option);
                    }
                    goto Method_Window_Step5;
                }
                goto Method_Window_Step4;
            Method_Window_Step5:
                var win_step5 = curMethod.Steps[5];
                var win_result5 = await inputer.Execute(win_step5.Options);
                if (inputer.isCancelled || win_result5 == null) { this.Cancel(); goto End; }

                if (win_result5.ValueX == null)
                {
                    goto Method_Window_Step5;
                }
                else
                {
                    this.firstPoint = (Vector2)win_result5.ValueX;
                }
                goto Method_Window_Step6;
            Method_Window_Step6:
                var win_step6 = curMethod.Steps[6];
                var win_result6 = await inputer.Execute(win_step6.Options);
                if (inputer.isCancelled || win_result6 == null) { this.Cancel(); goto End; }

                if (win_result6.ValueX == null)
                {
                    goto Method_Window_Step6;
                }
                else
                {
                    this.endPoint = (Vector2)win_result6.ValueX;
                }

                CreateTable();
                goto End;
        #endregion

        End:
                this.EndCreating();
        }

        public void CreateTable()
        {
            var doc = this.docRt.Document;
            DocumentManager.CurrentRecorder.BeginAction("Table");

            var table = doc.CreateObject<LcTable>();
            table.FirstPoint = this.firstPoint;
            table.ColumnCount = this.columnCount;
            table.RowHeight = this.rowHeight * this.height;
            table.CellTypes = this.cellTypes.Select(s => s.GetDescription()).ToArray();

            if (_methodName == TableInsertWay.BW.ToString())
            {
                table.EndPoint = this.endPoint;
                var tmp_widht = Math.Abs(this.endPoint.X - this.firstPoint.X);
                var tmp_height = Math.Abs(this.endPoint.Y - this.firstPoint.Y);
                var tmp_rowCount = (int)(tmp_height / this.rowHeight / this.height);
                // 至少三行：标题、表头、数据
                table.RowCount = Math.Max(tmp_rowCount, 3);
                table.ColumnWidth = tmp_widht / this.columnCount;
            }
            else
            {
                // 加上标题、表头行
                table.RowCount = this.rowCount + 2;
                table.ColumnWidth = this.columnWidth;
                // 根据宽高计算结束坐标
                table.EndPoint = new Vector2(table.FirstPoint.X + table.ColumnWidth * table.ColumnCount, table.FirstPoint.Y - table.RowHeight * table.RowCount);
            }

            table.Box2D = new Box2().SetFromPoints(table.FirstPoint, table.EndPoint);

            table.Cells = new List<LcTableCell>();
            // 创建单元格信息
            for (int row = 0; row < table.RowCount; row++)
            {
                var index = Math.Clamp(row, 0, 2);
                if ((cellTypes[index] == CellType.Title))
                {
                    var cell = doc.CreateObject<LcTableCell>();
                    cell.Init(table.FirstPoint, table.RowHeight, table.ColumnWidth, row, 0, table.ColumnCount);
                    table.Cells.Add(cell);
                    continue;
                }
                for (int col = 0; col < table.ColumnCount; col++)
                {
                    var cell = doc.CreateObject<LcTableCell>();

                    cell.Init(table.FirstPoint, table.RowHeight, table.ColumnWidth, row, col);
                    table.Cells.Add(cell);
                }
            }

            doc.ModelSpace.InsertElement(table);
            doc.ModelSpace.InsertElements(table.Cells);
            this.docRt.Action.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();

            (docEditor as DrawingEditRuntime).ActiveViewportRt.Control.AttachEvents(OnViewportMouseEvent, null, null, null, null);
        }

        protected override async void OnViewportMouseEvent(string type, MouseEventRuntime e)
        {
            base.OnViewportMouseEvent(type, e);
            // 双击判断鼠标坐标是否在单元格上
            if (e.Button == LcMouseButtons.Left && e.Clicks == 2)
            {
                LcElement hitEle = null;
                hitEle = this.vportRt.HitUnselect();
                if (hitEle != null)
                {
                    var tableCell = hitEle as LcTableCell;
                    var action = (tableCell.RtAction as TableEditAction);
                    var text = await action.ExecCreate();
                    tableCell.Set(text: text);
                    tableCell.Text = text;
                }
            }
        }

        public override void DrawAuxLines(SKCanvas canvas)
        {
            int rowCount;
            int colCount = this.columnCount;
            double width;
            double height = this.height * this.rowHeight;
            string[] cellTypes = this.cellTypes.Select(s => s.GetDescription()).ToArray();

            var mp = this.vportRt.PointerMovedPosition.ToVector2d();

            var start = this.firstPoint;
            var end = this.endPoint;
            if (start == null)
            {
                start = mp;
            }
            else
            {
                start = this.vportRt.ConvertWcsToScr(start);
                end = mp;
            }

            if (end != null)
            {
                var tmp_widht = Math.Abs(end.X - start.X);
                var tmp_height = Math.Abs(end.Y - start.Y);
                var tmp_rowCount = (int)(tmp_height / height / this.vportRt.Viewport.Scale);
                // 至少三行：标题、表头、数据
                rowCount = Math.Max(tmp_rowCount, 3);
                width = tmp_widht / colCount / this.vportRt.Viewport.Scale;
            }
            else
            {
                rowCount = this.rowCount + 2;
                width = this.columnWidth;
            }

            var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true };

            DrawCore(canvas, (float)width, (float)height, rowCount, colCount, cellTypes, start.ToSKPoint(), pen);
        }

        private void DrawCore(SKCanvas canvas, float width, float height, int rowCount, int colCount, string[] cellTypes, SKPoint start, SKPaint pen)
        {
            width *= (float)this.vportRt.Viewport.Scale;
            height *= (float)this.vportRt.Viewport.Scale;
            SKRect cellRect = new SKRect();

            for (int i = 0; i < rowCount; i++)
            {
                var index = Math.Clamp(i, 0, 2);
                if ((cellTypes[index] == CellType.Title.GetDescription()))
                {
                    cellRect.Left = start.X;
                    cellRect.Top = start.Y + i * height;
                    cellRect.Right = cellRect.Left + width * colCount;
                    cellRect.Bottom = cellRect.Top + height;

                    canvas.DrawRect(cellRect, pen);
                    continue;
                }
                for (int j = 0; j < colCount; j++)
                {
                    cellRect.Left = start.X + j * width;
                    cellRect.Top = start.Y + i * height;
                    cellRect.Right = cellRect.Left + width;
                    cellRect.Bottom = cellRect.Top + height;

                    // 绘制单元格边框
                    canvas.DrawRect(cellRect, pen);
                }
            }
        }

        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var table = element as LcTable;

            var grips = new List<ControlGrip>();

            var gripRightTop = new ControlGrip
            {
                Element = table,
                Name = "RightBottom",
                Position = table.Box2D.RightBottom
            };
            grips.Add(gripRightTop);

            return grips.ToArray();
        }

        private string _gripName;
        private Vector2 _position;
        private LcTable _table;

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var table = element as LcTable;

            _table = table;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                if (gripName == "RightBottom")
                {
                    // 得到新的结束点
                    var height = Math.Abs(_position.Y - table.FirstPoint.Y) / table.RowCount;
                    var width = Math.Abs(_position.X - table.FirstPoint.X) / table.ColumnCount;
                    _table.Set(end: _position, rowHeight: height, columnWidth: width);
                }
            }
        }

        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_table == null) return;

            if (_gripName == "RightTop")
            {

            }
        }
    }

    public enum CellType
    {
        [Description("标题")]
        Title,
        [Description("表头")]
        Header,
        [Description("数据")]
        Data,
    }

    public enum TableInsertWay
    {
        [Description("指定插入点")]
        BP,
        [Description("指定窗口")]
        BW,
    }
}
